//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import Foundation
import Testing
import SwiftBuild
import SWBProtocol
import SwiftBuildTestSupport
import SWBTestSupport
import SWBUtil

@Suite(.requireHostOS(.macOS))
fileprivate struct ProductPlannerTests {
    @Test(.requireSDKs(.iOS))
    func describeArchivableProducts() async throws {
        try await withTemporaryDirectory { temporaryDirectory in
            try await withAsyncDeferrable { deferrable in
                let testSession = try await TestSWBSession(temporaryDirectory: temporaryDirectory)
                await deferrable.addBlock {
                    await #expect(throws: Never.self) {
                            try await testSession.close()
                        }
                }

                let appTarget = try await testSession.session.sendMinimalTestingWorkspace(tmpDir: temporaryDirectory.path)

                // TODO: rdar://problem/56446029 Implement real tests for product planner

                let scheme = SWBSchemeInput(
                    name: "Test",
                    isShared: true,
                    isAutogenerated: false,
                    analyze: .init(configurationName: "Debug", targetIdentifiers: []),
                    archive: .init(configurationName: "Debug", targetIdentifiers: []),
                    profile: .init(configurationName: "Debug", targetIdentifiers: []),
                    run: .init(configurationName: "Debug", targetIdentifiers: [appTarget.guid]),
                    test: .init(configurationName: "Debug", targetIdentifiers: []))

                #expect(try await Set(testSession.session.describeArchivableProducts(input: [scheme])) == Set([
                    .init(displayName: "App", productName: "App", productType: .app, identifier: appTarget.guid, team: nil, bundleIdentifier: nil, destination: .init(platformName: "iOS", isSimulator: false), containingSchemes: ["Test"], iconPath: nil),
                    .init(displayName: "App", productName: "App", productType: .app, identifier: appTarget.guid, team: nil, bundleIdentifier: nil, destination: .init(platformName: "iOS Simulator", isSimulator: true), containingSchemes: ["Test"], iconPath: nil)
                ]))
            }
        }
    }

    @Test
    func describeSchemes() async throws {
        try await withTemporaryDirectory { temporaryDirectory in
            try await withAsyncDeferrable { deferrable in
                let testSession = try await TestSWBSession(temporaryDirectory: temporaryDirectory)
                await deferrable.addBlock {
                    await #expect(throws: Never.self) {
                            try await testSession.close()
                        }
                }

                let appTarget = try await testSession.session.sendMinimalTestingWorkspace(tmpDir: temporaryDirectory.path)

                // TODO: rdar://problem/56446029 Implement real tests for product planner

                let scheme = SWBSchemeInput(
                    name: "Test",
                    isShared: true,
                    isAutogenerated: false,
                    analyze: .init(configurationName: "Debug", targetIdentifiers: []),
                    archive: .init(configurationName: "Debug", targetIdentifiers: []),
                    profile: .init(configurationName: "Debug", targetIdentifiers: []),
                    run: .init(configurationName: "Debug", targetIdentifiers: [appTarget.guid]),
                    test: .init(configurationName: "Debug", targetIdentifiers: []))

                #expect(try await testSession.session.describeSchemes(input: [scheme]) == [.init(name: "Test", disambiguatedName: "Test", isShared: true, isAutogenerated: false, actions: .init(analyze: .init(configurationName: "Debug", products: [], testPlans: []), archive: .init(configurationName: "Debug", products: [], testPlans: []), profile: .init(configurationName: "Debug", products: [], testPlans: []), run: .init(configurationName: "Debug", products: [.init(displayName: "App", identifier: appTarget.guid, supportedDestinations: [])], testPlans: []), test: .init(configurationName: "Debug", products: [], testPlans: [])))])
            }
        }
    }

    @Test(.requireSDKs(.macOS))
    func describeProducts() async throws {
        try await withTemporaryDirectory { temporaryDirectory in
            try await withAsyncDeferrable { deferrable in
                let testSession = try await TestSWBSession(temporaryDirectory: temporaryDirectory)
                await deferrable.addBlock {
                    await #expect(throws: Never.self) {
                            try await testSession.close()
                        }
                }

                let appTarget = try await testSession.session.sendMinimalTestingWorkspace(tmpDir: temporaryDirectory.path)

                // TODO: rdar://problem/56446029 Implement real tests for product planner

                #expect(try await testSession.session.describeProducts(input: .init(configurationName: "Debug", targetIdentifiers: [appTarget.guid]), platformName: "macosx") == [.init(displayName: "App", productName: "App", identifier: "App", productType: .app, dependencies: nil, bundleIdentifier: nil, targetedDeviceFamilies: nil, deploymentTarget: "10.10", marketingVersion: nil, buildVersion: nil, enableBitcode: false, codesign: nil, team: nil, infoPlistPath: nil, iconPath: nil)])
            }
        }
    }
}

extension SWBBuildServiceSession {
    fileprivate func sendMinimalTestingWorkspace(tmpDir: Path) async throws -> TestStandardTarget {
        let appTarget = TestStandardTarget(
            "App",
            type: .application,
            buildConfigurations: [
                TestBuildConfiguration(
                    "Debug",
                    buildSettings: [
                        "PRODUCT_NAME": "$(TARGET_NAME)",
                        "SDKROOT": "iphoneos",
                    ])
            ],
            buildPhases: [
                TestSourcesBuildPhase([
                    TestBuildFile("TestFile1.c"),
                    TestBuildFile("TestFile2.c"),
                    TestBuildFile("TestFile3.c"),
                    TestBuildFile("TestFile4.swift"),
                ])
            ]
        )

        try await sendPIF(.init(TestWorkspace("Test", sourceRoot: tmpDir, projects: [
            TestProject(
                "Test",
                groupTree: TestGroup("Test", children: [
                    TestFile("TestFile1.c"),
                    TestFile("TestFile2.c"),
                    TestFile("TestFile3.c"),
                    TestFile("TestFile4.swift"),
                ]),
                buildConfigurations: [
                    TestBuildConfiguration("Debug")
                ],
                targets: [
                    appTarget
                ]
            )
        ]).toObjects().propertyListItem))

        return appTarget
    }
}
